package ttt;

import java.util.Random;

public class TicTacToeGame
{
	private static final int ROWS 			= 3;
	private static final int COLUMNS		= 3;
	
	private static final int HUMAN        	= 0; 
	private static final int COMPUTER     	= 1; 
	public  static final int EMPTY        	= 2;

	public  static final int HUMAN_WIN    	= 0;
	public  static final int DRAW         	= 1;
	public  static final int UNCLEAR     	= 2;
	public  static final int COMPUTER_WIN 	= 3;

	private int [][] board 		= 	new int[ ROWS ][ COLUMNS ];
    private Random random		=	new Random();  
	private int side			=	random.nextInt(2);  
	private int position		=	UNCLEAR;
	private char computerChar;
	private char humanChar;

	// Constructor
	public TicTacToeGame(){
		clearBoard();
		initSide();
	}
	
	private void initSide(){
		
	    if( this.side == COMPUTER ){
	    	computerChar 	= 'X'; 
	    	humanChar 		= 'O'; 
	    }else{
	    	computerChar	= 'O';
	    	humanChar		= 'X'; 
	    }
    }
    
    public void setComputerPlays(){
    	
        this.side = COMPUTER;
        initSide();
    }
    
    public void setHumanPlays(){
    	
        this.side = HUMAN;
        initSide();
    }

	public boolean computerPlays(){
		
	    return side == COMPUTER;
	}

	public int chooseMove(){
	    Best best = chooseMove(COMPUTER);
	    return best.row * 3 + best.column;
    }
    
    // Find optimal move
	private Best chooseMove(int side){
		
		int opponent;              // The other side
		Best reply;           // Opponent's best reply
		int simpleEvaluation;       // Result of an immediate evaluation
		int bestRow = 0;
		int bestColumn = 0;
		int value = Integer.MIN_VALUE;

		if( (simpleEvaluation = positionValue()) != UNCLEAR ){
			return new Best( simpleEvaluation);
		}

        if(side == COMPUTER){
            opponent = HUMAN;
        } else if(side == HUMAN){
            opponent = COMPUTER;
        } else {
            throw new IllegalArgumentException("Given side does not exist!");
        }

        for(int row = 0; row < ROWS; row++){
            for(int column = 0; column < COLUMNS; column++){
                if(squareIsEmpty(row, column)){
                    TicTacToeGame copy = this.copy();
                    copy.place(row, column, side);
                    reply = copy.chooseMove(opponent);
                    if(value < -reply.val){
                        value = - reply.val;
                        bestRow = row;
                        bestColumn = column;
                    }
                }
            }
        }

	    return new Best(value, bestRow, bestColumn);
    }

    private TicTacToeGame copy(){
        TicTacToeGame copy = new TicTacToeGame();

        if(this.computerPlays()){
            copy.setComputerPlays();
        } else {
            copy.setHumanPlays();
        }

        for(int row = 0; row < ROWS; row++){
            for(int column = 0; column < COLUMNS; column++){
                copy.place(row, column, board[row][column]);
            }
        }

        return copy;
    }
   
    //check if move ok
    public boolean moveOk(int move){
    	
	 	return ( move>=0 && move <=8 && board[move/3 ][ move%3 ] == EMPTY );
    }
    
    // play move
    public void playMove(int move){
    	
		board[move/3][move%3] = this.side;
		if (side == COMPUTER){
			this.side=HUMAN;
		}else{
			this.side=COMPUTER;
		}
	}


	// Simple supporting routines
	private void clearBoard(){
        for(int row = 0; row < ROWS; row++){
            for(int column = 0; column < COLUMNS; column++){
                this.board[row][column] = EMPTY;
            }
        }
	}


	private boolean boardIsFull(){
		boolean isFull = true;
		for(int row = 0; row < ROWS; row++){
            for(int column = 0; column < COLUMNS; column++){
                if(squareIsEmpty(row, column)){
                    isFull = false;
                }
            }
        }
		return isFull;
	}

	// Returns whether 'side' has won in this position
	private boolean isAWin(int side){
        if(side != COMPUTER && side != HUMAN){
            throw new IllegalArgumentException("The given side does not exist!");
        }
        boolean isAWin = false;
        if(board[1][1] == side){
            if(board[0][0] == side && board[2][2] == side){
                isAWin = true;
            } else if(board[0][2] == side && board[2][0] == side){
                isAWin = true;
            } else if(board[0][1] == side && board[2][1] == side){
                isAWin = true;
            } else if(board[1][0] == side && board[1][2] == side){
                isAWin = true;
            }
        }
        if(board[0][0] == side){
            if(board[0][1] == side && board[0][2] == side){
                isAWin = true;
            } else if(board[1][0] == side && board[2][0] == side){
                isAWin = true;
            }
        }
        if(board[2][2] == side){
            if(board[1][2] == side && board[0][2] == side){
                isAWin = true;
            } else if(board[2][1] == side && board[2][0] == side){
                isAWin = true;
            }
        }
	    return isAWin;
    }

	// Play a move, possibly clearing a square
	private void place(int row, int column, int piece){
		
		board[row][column] = piece;
	}

	private boolean squareIsEmpty(int row, int column){
		return board[ row ][ column ] == EMPTY;
	}

	// Compute static value of current position (win, draw, etc.)
	private int positionValue(){
		if(isAWin(COMPUTER)){
            return COMPUTER_WIN;
        } else if(isAWin(HUMAN)){
            return HUMAN_WIN;
        } else if(boardIsFull()){
            return DRAW;
        } else{
            return UNCLEAR;
        }
	}
	
	
	public String toString()	{
	    //TODO:
        StringBuilder buffer = new StringBuilder();
        String indentation = " ";
        String horizontalLine = "___________";
        String verticalLine = "|";
        String newLine = "\n";

        buffer.append("Human : ").append(humanChar);
        buffer.append(newLine);
        buffer.append("Computer : ").append(computerChar);
        buffer.append(newLine);

        for(int row = 0; row < ROWS; row++){
            for(int column = 0; column < COLUMNS; column++){
                int currentLocation = board[row][column];
                buffer.append(indentation);
                if(currentLocation == COMPUTER){
                    buffer.append(computerChar);
                }else if( currentLocation == HUMAN){
                    buffer.append(humanChar);
                }else{
                    buffer.append(indentation);
                }
                buffer.append(indentation);
                if(column != COLUMNS -1){
                    buffer.append(verticalLine);
                }
            }
            if(row != ROWS - 1){
                buffer.append(newLine);
                buffer.append(horizontalLine);
                buffer.append(newLine);
            }
        }

		return buffer.toString();
	}  
	
	public boolean gameOver(){
	    this.position = positionValue();
	    return this.position != UNCLEAR;
    }
    
    public String winner() {
        if(this.position==COMPUTER_WIN){
        	return "computer";
        }else if (this.position==HUMAN_WIN){
        	return "human";
        }else{
        	return "nobody";
        }
    }
    
/**	
 * 
 * PRIVATE INNER CLASS
 *
 */
	
private class Best{
	int row;
    int column;
    int val;

    public Best(int v){
    	this(v, 0, 0);
    }
      
    public Best(int v, int r, int c){
    	val = v;
    	row = r;
    	column = c;
    }
} 
	
	
}

